<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>事务隔离级别与锁模式</title>
    <style>
        body {
            background-color: #c7edcc
        }
    </style>
</head>
<body>
<pre>
    ISO规定的4个标准隔离级别,由低到高依次为:

    Read uncommitted 读未提交, 一个事务可以读到另一个事务未提交的数据,会读取到另一个事务的中间数据(脏读)
    Read committed、
    Repeatable read、 Mysql的默认隔离级别就是Repeatable read
    Serializable

    数据库并发读写会出现的问题:

    1. 脏读(事务没提交，提前读取)：脏读就是指当一个事务正在访问数据，并且对数据进行了修改，而这种修改还没有提交到数据库中，这时，另外一个事务也访问这个数据，然后使用了这个数据。

    2. 不可重复读(两次读的不一致) ：是指在一个事务内，多次读同一数据。在这个事务还没有结束时，另外一个事务也访问该同一数据。那么，在第一个事务中的两次读数据之间，由于第二个事务的修改，
        那么第一个事务两次读到的的数据可能是不一样的。这样就发生了在一个事务内两次读到的数据是不一样的，因此称为是不可重复读。例如，一个编辑人员两次读取同一文档，但在两次读取之间，作者重写了该文档。
        当编辑人员第二次读取文档时，文档已更改。原始读取不可重复。如果只有在作者全部完成编写后编辑人员才可以读取文档，则可以避免该问题。

    3. 幻读 : 是指当事务不是独立执行时发生的一种现象，例如第一个事务对一个表中的数据进行了修改，这种修改涉及到表中的全部数据行。同时，第二个事务也修改这个表中的数据，这种修改是向表中插入一行新数据。
        那么，以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行，就好象发生了幻觉一样。例如，一个编辑人员更改作者提交的文档，但当生产部门将其更改内容合并到该文档的主复本时，
        发现作者已将未编辑的新材料添加到该文档中。如果在编辑人员和生产部门完成对原始文档的处理之前，任何人都不能将新材料添加到文档中，则可以避免该问题。

    4.第一类更新丢失(回滚丢失)： 当2个事务更新相同的数据源，如果第一个事务被提交，而另外一个事务却被撤销，那么会连同第一个事务所做的跟新也被撤销。也就是说第一个事务做的跟新丢失了。

    5.第二类更新丢失(覆盖丢失)： 第二类更新丢失实在实际应用中经常遇到的并发问题，他和不可重复读本质上是同一类并发问题，通常他被看做不可重复读的特例：当2个或这个多个事务查询同样的记录然后各自基于最初的查询结果更新该行时，
        会造成第二类丢失更新。因为每个事务都不知道不知道其他事务的存在，最后一个事务对记录做的修改将覆盖其他事务对该记录做的已提交的跟新...


    幻影读(phantom read)
    在事务执行过程中，当两个完全相同的查询语句执行得到不同的结果集。这种现象称为“幻影读(phantom read)”


    隔离级别vs读现象(Isolation Levels vs Read Phenomena)

    隔离级别	脏读		不可重复读		幻影读
    未提交读	可能发生	可能发生		可能发生
    提交读	-		可能发生		可能发生
    可重复读	-		-			可能发生
    可序列化	-		-			-

    MYSQL如何实现事务隔离级别?
        在innodb存储引擎中,表自动加入了两列,用于实现并发控制

    锁模式?


    访问数据库与内存数据的区别?
        内存中的数据读写与数据库读写有很多相似,抛开内存和硬盘主要区别(读写速度,内存数据断电丢失而硬盘不会),在数据库中遇到的问题,在写代码的时候也会遇到的.
        对于并发访问的内存数据,程序需要同步,避免线程安全问题,这就需要使用到锁.写代码时一般比较暴力,在修改数据的代码外加上一个synchronized块,这个如同数据
        库中的write lock,这个锁是排它的,会导致其它线程挂起,而当读取数据的时候如果有写入操作,java中采用happen-before原则,比如对于一个volatile变量,set之后
        get总可以读取到最新值,也许这里一个set操作,底层代码采用了内存屏障和禁止重排序等操作,java代码只有遵守这种规则.

        对于MySQL,innodb存储引擎中,表自动加入了两列,用于实现并发控制.一列表示创建时间,一列表示更新时间,每个事务创建时都有一个开始时间,为了避免脏读,比如一个
        查询,只会返回创建时间大于当前事务开始时间,而更新时间小于事务开始时间的记录.

</pre>
</body>
</html>